/*
 * Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
 * <p>
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.rzcf.blink.pay.infrastructure.persistent.repository.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rzcf.blink.pay.domain.enums.OrderPayStatusEnum;
import com.rzcf.blink.pay.domain.model.entity.PayOrderEntity;
import com.rzcf.blink.pay.domain.repository.PayOrderRepository;
import com.rzcf.blink.pay.infrastructure.persistent.mapper.PayOrderMapper;
import com.rzcf.blink.pay.infrastructure.persistent.po.PayOrder;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 支付订单表 服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2021-04-27
 */
@Service
@RequiredArgsConstructor
public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> implements PayOrderRepository {

    private final PayOrderMapper payOrderMapper;

    /**
     * 更新订单状态  【订单生成】 --》 【支付中】
     **/
    @Override
    public boolean updateInit2Ing(String payOrderId, PayOrderEntity payOrder) {

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(OrderPayStatusEnum.STATE_ING.getCode());

        //同时更新， 未确定 --》 已确定的其他信息。  如支付接口的确认、 费率的计算。
        updateRecord.setIfCode(payOrder.getIfCode());
        updateRecord.setWayCode(payOrder.getWayCode());
        updateRecord.setMchFeeRate(payOrder.getMchFeeRate());
        updateRecord.setMchFeeAmount(payOrder.getMchFeeAmount());
        updateRecord.setChannelUser(payOrder.getChannelUser());
        updateRecord.setChannelOrderNo(payOrder.getChannelOrderNo());

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, OrderPayStatusEnum.STATE_INIT.getCode()));
    }

    @Override
    /** 更新订单状态  【支付中】 --》 【支付成功】 **/
    public boolean updateIng2Success(String payOrderId, String channelOrderNo, String channelUserId) {

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(OrderPayStatusEnum.STATE_SUCCESS.getCode());
        updateRecord.setChannelOrderNo(channelOrderNo);
        updateRecord.setChannelUser(channelUserId);
        updateRecord.setSuccessTime(new Date());

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, OrderPayStatusEnum.STATE_ING.getCode()));
    }

    /**
     * 更新订单状态  【支付中】 --》 【订单关闭】
     **/
    @Override
    public boolean updateIng2Close(String payOrderId) {

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(OrderPayStatusEnum.STATE_CLOSED.getCode());

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, OrderPayStatusEnum.STATE_ING.getCode()));
    }

    /**
     * 更新订单状态  【订单生成】 --》 【订单关闭】
     **/
    @Override
    public boolean updateInit2Close(String payOrderId) {

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(OrderPayStatusEnum.STATE_CLOSED.getCode());

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, OrderPayStatusEnum.STATE_INIT.getCode()));
    }


    /**
     * 更新订单状态  【支付中】 --》 【支付失败】
     **/
    public boolean updateIng2Fail(String payOrderId, String channelOrderNo, String channelUserId, String channelErrCode, String channelErrMsg) {

        PayOrder updateRecord = new PayOrder();
        updateRecord.setState(OrderPayStatusEnum.STATE_FAIL.getCode());
        updateRecord.setErrCode(channelErrCode);
        updateRecord.setErrMsg(channelErrMsg);
        updateRecord.setChannelOrderNo(channelOrderNo);
        updateRecord.setChannelUser(channelUserId);

        return update(updateRecord, new LambdaUpdateWrapper<PayOrder>()
                .eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getState, OrderPayStatusEnum.STATE_ING.getCode()));
    }


    /**
     * 更新订单状态  【支付中】 --》 【支付成功/支付失败】
     **/
    @Override
    public boolean updateIng2SuccessOrFail(String payOrderId, Integer updateState, String channelOrderNo, String channelUserId, String channelErrCode, String channelErrMsg) {

        if (updateState == OrderPayStatusEnum.STATE_ING.getCode().intValue()) {
            return true;
        } else if (updateState == OrderPayStatusEnum.STATE_SUCCESS.getCode().intValue()) {
            return updateIng2Success(payOrderId, channelOrderNo, channelUserId);
        } else if (updateState == OrderPayStatusEnum.STATE_FAIL.getCode().intValue()) {
            return updateIng2Fail(payOrderId, channelOrderNo, channelUserId, channelErrCode, channelErrMsg);
        }
        return false;
    }

    /**
     * 查询商户订单
     **/
    @Override
    public PayOrderEntity queryMchOrder(String mchNo, String payOrderId, String mchOrderNo) {

        if (StringUtils.isNotEmpty(payOrderId)) {
            return BeanUtil.copyProperties(getOne(PayOrder.gw().eq(PayOrder::getMchNo, mchNo).eq(PayOrder::getPayOrderId, payOrderId)), PayOrderEntity.class);
        } else if (StringUtils.isNotEmpty(mchOrderNo)) {
            return BeanUtil.copyProperties(getOne(PayOrder.gw().eq(PayOrder::getMchNo, mchNo).eq(PayOrder::getMchOrderNo, mchOrderNo)), PayOrderEntity.class);
        } else {
            return null;
        }
    }

    @Override
    public PayOrderEntity queryById(String payOrderId) {
        return BeanUtil.copyProperties(this.getById(payOrderId), PayOrderEntity.class);
    }


    public Map payCount(String mchNo, Byte state, Byte refundState, String dayStart, String dayEnd) {
        Map param = new HashMap<>();
        if (state != null) {
            param.put("state", state);
        }
        if (refundState != null) {
            param.put("refundState", refundState);
        }
        if (StrUtil.isNotBlank(mchNo)) {
            param.put("mchNo", mchNo);
        }
        if (StrUtil.isNotBlank(dayStart)) {
            param.put("createTimeStart", dayStart);
        }
        if (StrUtil.isNotBlank(dayEnd)) {
            param.put("createTimeEnd", dayEnd);
        }
        return payOrderMapper.payCount(param);
    }

    public List<Map> payTypeCount(String mchNo, Byte state, Byte refundState, String dayStart, String dayEnd) {
        Map param = new HashMap<>();
        if (state != null) {
            param.put("state", state);
        }
        if (refundState != null) {
            param.put("refundState", refundState);
        }
        if (StrUtil.isNotBlank(mchNo)) {
            param.put("mchNo", mchNo);
        }
        if (StrUtil.isNotBlank(dayStart)) {
            param.put("createTimeStart", dayStart);
        }
        if (StrUtil.isNotBlank(dayEnd)) {
            param.put("createTimeEnd", dayEnd);
        }
        return payOrderMapper.payTypeCount(param);
    }

    /**
     * 更新订单为 超时状态
     **/
    public Integer updateOrderExpired() {

        PayOrder payOrder = new PayOrder();
        payOrder.setState(OrderPayStatusEnum.STATE_CLOSED.getCode());

        return baseMapper.update(payOrder,
                PayOrder.gw()
                        .in(PayOrder::getState, Arrays.asList(OrderPayStatusEnum.STATE_INIT.getCode(), OrderPayStatusEnum.STATE_ING.getCode()))
                        .le(PayOrder::getExpiredTime, new Date())
        );
    }
}
